package com.rpc.proxys;

import com.rpc.messages.MessageReq;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.net.Socket;
import java.util.concurrent.atomic.AtomicLong;

/**
 * @Auther: pengjf
 * @Date: 2018-08-06 14:54
 * @Description:针对客户端反射的方式调用socket来访问远程的服务如同访问本地的服务一样
 */
public class ProxyForSocket<T> {
    private static AtomicLong reqId=new AtomicLong(0);
    public  static<T> T getClientProxy(final Class<T> classz,final String host,final int port){
        //通过此方法来获取要生成的相应的方式
      return (T) Proxy.newProxyInstance(classz.getClassLoader(), new Class[]{classz}, new InvocationHandler() {
            @Override
            public Object invoke(Object o, Method method, Object[] objects) throws Throwable {

                return  sendNetworkMessage(classz,method,objects,host,port);
            }
        });

     }

    /***
     *
     * 代理对象实例
     * @param method 方法
     * @param objects 参数
     * @return 返回结果
     */
     public static Object sendNetworkMessage(Class clazz, Method method, Object[] objects,final String host,final int port){
        //调用的时候,无非就是发送对象数据,暂时简单封装MessageReq MessageResp两个类,初级版本直接java本身对得序列化
        //后面版本进行再优化
         MessageReq req=new MessageReq();
         req.setClassName(clazz.getName());
         req.setArgs(objects);
         req.setMethod(method.getName());
         req.setReqId(reqId.incrementAndGet());
         req.setArgsType(method.getParameterTypes());
         Socket socket = null;
         ObjectOutputStream oos=null;
         ObjectInputStream  ois=null;
         try {
              socket =new Socket(host,port);
              oos=new ObjectOutputStream(socket.getOutputStream());
              oos.writeObject(req);
              oos.flush();
              ois=new ObjectInputStream(socket.getInputStream());
              return ois.readObject();
         } catch (IOException e) {
             e.printStackTrace();
         } catch (ClassNotFoundException e) {
             e.printStackTrace();
         }finally {
             if(oos!=null){
                 try {
                     oos.close();
                 } catch (IOException e) {
                     e.printStackTrace();
                 }
             }
             if(ois!=null){
                 try {
                     ois.close();
                 } catch (IOException e) {
                     e.printStackTrace();
                 }
             }
             if (socket!=null || !socket.isClosed()){
                 try {
                     socket.close();
                 } catch (IOException e) {
                     e.printStackTrace();
                 }
             }
         }
         return null;
     }

}
